﻿var __extends = this.__extends || function (d, b) {
    function __() { this.constructor = d; }
    __.prototype = b.prototype;
    d.prototype = new __();
};
var Geo;
(function (Geo) {
    (function (CoordinateConverter) {
        (function (Enumerations) {
            (function (DirectionTypes) {
                DirectionTypes._map = [];
                DirectionTypes._map[0] = "North";
                DirectionTypes.North = 0;
                DirectionTypes._map[1] = "East";
                DirectionTypes.East = 1;
                DirectionTypes._map[2] = "South";
                DirectionTypes.South = 2;
                DirectionTypes._map[3] = "West";
                DirectionTypes.West = 3;
            })(Enumerations.DirectionTypes || (Enumerations.DirectionTypes = {}));
            var DirectionTypes = Enumerations.DirectionTypes;
            (function (LatitudeLongitudeTypes) {
                LatitudeLongitudeTypes._map = [];
                LatitudeLongitudeTypes._map[0] = "Latitude";
                LatitudeLongitudeTypes.Latitude = 0;
                LatitudeLongitudeTypes._map[1] = "Longitude";
                LatitudeLongitudeTypes.Longitude = 1;
            })(Enumerations.LatitudeLongitudeTypes || (Enumerations.LatitudeLongitudeTypes = {}));
            var LatitudeLongitudeTypes = Enumerations.LatitudeLongitudeTypes;
        })(CoordinateConverter.Enumerations || (CoordinateConverter.Enumerations = {}));
        var Enumerations = CoordinateConverter.Enumerations;
                (function (Model) {
            var CoordinateDecimalInfo = (function () {
                function CoordinateDecimalInfo(decimalLatitude, decimalLongitude) {
                    this.Latitude = decimalLatitude;
                    this.Longitude = decimalLongitude;
                }
                CoordinateDecimalInfo.prototype.ToString = function () {
                    return this.Latitude.toString() + ', ' + this.Longitude.toString();
                };
                CoordinateDecimalInfo.prototype.ToCoordinateDecimal = function () {
                    return this;
                };
                CoordinateDecimalInfo.prototype.ToCoordinateDms = function () {
                    return new CoordinateDmsInfo(this.NumberToDms(Enumerations.LatitudeLongitudeTypes.Latitude, this.Latitude), this.NumberToDms(Enumerations.LatitudeLongitudeTypes.Longitude, this.Longitude));
                };
                CoordinateDecimalInfo.prototype.ToCoordinateDm = function () {
                    return new CoordinateDmInfo(this.NumberToDms(Enumerations.LatitudeLongitudeTypes.Latitude, this.Latitude).ToDm(), this.NumberToDms(Enumerations.LatitudeLongitudeTypes.Longitude, this.Longitude).ToDm());
                };
                CoordinateDecimalInfo.prototype.NumberToDms = function (latitudeLongitudeType, coordinate) {
                    var result;
                    var degrees;
                    var minutes;
                    var seconds;
                    var modDegrees = Math.abs(coordinate % 1);
                    var degrees = Math.round(Math.abs(coordinate) - modDegrees);
                    var rawMinutes = modDegrees * 60;
                    var modMinutes = rawMinutes % 1;
                    var minutes = Math.round(rawMinutes - modMinutes);
                    var seconds = parseFloat((modMinutes * 60).toPrecision(6));
                    var resultDirectionType;
                    if(latitudeLongitudeType == Enumerations.LatitudeLongitudeTypes.Latitude) {
                        resultDirectionType = (coordinate > 0) ? Enumerations.DirectionTypes.North : Enumerations.DirectionTypes.South;
                    } else {
                        resultDirectionType = (coordinate > 0) ? Enumerations.DirectionTypes.East : Enumerations.DirectionTypes.West;
                    }
                    return new Model.DmsInfo(resultDirectionType, Math.abs(degrees), minutes, seconds);
                };
                return CoordinateDecimalInfo;
            })();
            Model.CoordinateDecimalInfo = CoordinateDecimalInfo;            
            var CoordinateDmInfo = (function () {
                function CoordinateDmInfo(dmLatitude, dmLongitude) {
                    this._dmLatitude = dmLatitude;
                    this._dmLongitude = dmLongitude;
                }
                Object.defineProperty(CoordinateDmInfo.prototype, "DmLatitude", {
                    get: function () {
                        return this._dmLatitude;
                    },
                    enumerable: true,
                    configurable: true
                });
                Object.defineProperty(CoordinateDmInfo.prototype, "DmLongitude", {
                    get: function () {
                        return this._dmLongitude;
                    },
                    enumerable: true,
                    configurable: true
                });
                CoordinateDmInfo.prototype.ToString = function () {
                    return this.DmLatitude.ToString() + ', ' + this.DmLongitude.ToString();
                };
                CoordinateDmInfo.prototype.ToCoordinateDecimal = function () {
                    return new CoordinateDecimalInfo(this.DmLatitude.ToDecimal(), this.DmLongitude.ToDecimal());
                };
                CoordinateDmInfo.prototype.ToCoordinateDms = function () {
                    return new CoordinateDmsInfo(this.DmLatitude.ToDms(), this.DmLongitude.ToDms());
                };
                CoordinateDmInfo.prototype.ToCoordinateDm = function () {
                    return this;
                };
                return CoordinateDmInfo;
            })();
            Model.CoordinateDmInfo = CoordinateDmInfo;            
            var CoordinateDmsInfo = (function () {
                function CoordinateDmsInfo(dmsLatitude, dmsLongitude) {
                    this._dmsLatitude = dmsLatitude;
                    this._dmsLongitude = dmsLongitude;
                }
                Object.defineProperty(CoordinateDmsInfo.prototype, "DmsLatitude", {
                    get: function () {
                        return this._dmsLatitude;
                    },
                    enumerable: true,
                    configurable: true
                });
                Object.defineProperty(CoordinateDmsInfo.prototype, "DmsLongitude", {
                    get: function () {
                        return this._dmsLongitude;
                    },
                    enumerable: true,
                    configurable: true
                });
                CoordinateDmsInfo.prototype.ToString = function () {
                    return this.DmsLatitude.ToString() + ', ' + this.DmsLongitude.ToString();
                };
                CoordinateDmsInfo.prototype.ToCoordinateDecimal = function () {
                    return new CoordinateDecimalInfo(this.DmsLatitude.ToDecimal(), this.DmsLongitude.ToDecimal());
                };
                CoordinateDmsInfo.prototype.ToCoordinateDms = function () {
                    return this;
                };
                CoordinateDmsInfo.prototype.ToCoordinateDm = function () {
                    return new CoordinateDmInfo(this.DmsLatitude.ToDm(), this.DmsLongitude.ToDm());
                };
                return CoordinateDmsInfo;
            })();
            Model.CoordinateDmsInfo = CoordinateDmsInfo;            
            var CoordinateBase = (function () {
                function CoordinateBase() {
                }
                CoordinateBase.prototype.GetDirectionAbbreviation = function (directionType) {
                    var result;
                    if(directionType == Enumerations.DirectionTypes.North) {
                        result = 'N';
                    } else if(directionType == Enumerations.DirectionTypes.East) {
                        result = 'E';
                    } else if(directionType == Enumerations.DirectionTypes.South) {
                        result = 'S';
                    } else if(directionType == Enumerations.DirectionTypes.West) {
                        result = 'W';
                    }
                    return result;
                };
                return CoordinateBase;
            })();
            Model.CoordinateBase = CoordinateBase;            
            var DmInfo = (function (_super) {
                __extends(DmInfo, _super);
                function DmInfo(directionType, degrees, minutes) {
                                _super.call(this);
                    this._directionType = directionType;
                    this._degrees = degrees;
                    this._minutes = minutes;
                }
                Object.defineProperty(DmInfo.prototype, "DirectionType", {
                    get: function () {
                        return this._directionType;
                    },
                    enumerable: true,
                    configurable: true
                });
                Object.defineProperty(DmInfo.prototype, "Degrees", {
                    get: function () {
                        return this._degrees;
                    },
                    enumerable: true,
                    configurable: true
                });
                Object.defineProperty(DmInfo.prototype, "Minutes", {
                    get: function () {
                        return this._minutes;
                    },
                    enumerable: true,
                    configurable: true
                });
                DmInfo.prototype.ToDecimal = function () {
                    var result;
                    var multiplier = (this.DirectionType === Enumerations.DirectionTypes.West || this.DirectionType === Enumerations.DirectionTypes.South) ? -1 : 1;
                    var result = multiplier * (this.Degrees + (this.Minutes / 60.0));
                    return parseFloat(result.toPrecision(10));
                };
                DmInfo.prototype.ToDm = function () {
                    return this;
                };
                DmInfo.prototype.ToDms = function () {
                    var result;
                    var modMinutes = this.Minutes % 1;
                    var minutesResult = Math.round(this.Minutes - modMinutes);
                    var secondsResult = parseFloat((modMinutes * 60).toPrecision(6));
                    return new Model.DmsInfo(this.DirectionType, Math.abs(this.Degrees), minutesResult, secondsResult);
                };
                DmInfo.prototype.ToString = function () {
                    return this.GetDirectionAbbreviation(this.DirectionType) + ' ' + this.Degrees + '°' + this.Minutes + '"';
                };
                return DmInfo;
            })(CoordinateBase);
            Model.DmInfo = DmInfo;            
            var DmsInfo = (function (_super) {
                __extends(DmsInfo, _super);
                function DmsInfo(directionType, degrees, minutes, seconds) {
                                _super.call(this);
                    this._directionType = directionType;
                    this._degrees = degrees;
                    this._minutes = minutes;
                    this._seconds = seconds;
                }
                Object.defineProperty(DmsInfo.prototype, "DirectionType", {
                    get: function () {
                        return this._directionType;
                    },
                    enumerable: true,
                    configurable: true
                });
                Object.defineProperty(DmsInfo.prototype, "Degrees", {
                    get: function () {
                        return this._degrees;
                    },
                    enumerable: true,
                    configurable: true
                });
                Object.defineProperty(DmsInfo.prototype, "Minutes", {
                    get: function () {
                        return this._minutes;
                    },
                    enumerable: true,
                    configurable: true
                });
                Object.defineProperty(DmsInfo.prototype, "Seconds", {
                    get: function () {
                        return this._seconds;
                    },
                    enumerable: true,
                    configurable: true
                });
                DmsInfo.prototype.ToDecimal = function () {
                    var multiplier = (this.DirectionType === Enumerations.DirectionTypes.West || this.DirectionType === Enumerations.DirectionTypes.South) ? -1 : 1;
                    var result = multiplier * (this.Degrees + (this.Minutes / 60.0) + (this.Seconds / 3600.0));
                    return parseFloat(result.toPrecision(10));
                };
                DmsInfo.prototype.ToDm = function () {
                    var resultMinutes = (this.Seconds / 60) + this.Minutes;
                    return new Model.DmInfo(this.DirectionType, Math.abs(this.Degrees), resultMinutes);
                };
                DmsInfo.prototype.ToDms = function () {
                    return this;
                };
                DmsInfo.prototype.ToString = function () {
                    return this.GetDirectionAbbreviation(this.DirectionType) + ' ' + this.Degrees + '°' + this.Minutes + '\'' + this.Seconds + '"';
                };
                return DmsInfo;
            })(CoordinateBase);
            Model.DmsInfo = DmsInfo;            
        })(CoordinateConverter.Model || (CoordinateConverter.Model = {}));
        var Model = CoordinateConverter.Model;
        (function (Providers) {
            var DecimalAndDmsConverter = (function () {
                function DecimalAndDmsConverter() { }
                DecimalAndDmsConverter.prototype.TryParseCoordinateDms = function (raw, coordinate) {
                    try  {
                        coordinate = this.ParseCoordinateDms(raw);
                        return true;
                    } catch (ex) {
                        return false;
                    }
                };
                DecimalAndDmsConverter.prototype.ParseCoordinateDms = function (raw) {
                    if(raw == null) {
                        return null;
                    }
                    var result;
                    var rawStripped = raw.replace(/[^nesw0-9-,\.]/ig, ' ').replace(/\s{2,}/ig, ' ');
                    var latitudePart;
                    var longitudePart;
                    if(rawStripped.indexOf(',') > 0) {
                        if(rawStripped.indexOf(',') !== rawStripped.lastIndexOf(',')) {
                            throw 'ParseCoordinateDms Invalid Coordinate Format: multable [,]';
                        }
                        result = this.ToCoordinateDmsFromArray(rawStripped.split(','));
                    } else if(rawStripped.indexOf(' ') > 0) {
                        var coordinateParts = rawStripped.split(' ');
                        var coordinatePart1 = '';
                        var coordinatePart2 = '';
                        var maxNumericSegments = Math.floor(coordinateParts.length / 2);
                        var numericSegments = 0;
                        for(var i = 0; i < coordinateParts.length; i++) {
                            if(i < coordinateParts.length / 2 && numericSegments < maxNumericSegments) {
                                coordinatePart1 += coordinateParts[i] + ' ';
                            } else {
                                coordinatePart2 += coordinateParts[i] + ' ';
                            }
                            if(!isNaN(parseFloat(coordinateParts[i]))) {
                                numericSegments += 1;
                            }
                        }
                        result = this.ToCoordinateDmsFromArray([
                            coordinatePart1, 
                            coordinatePart2
                        ]);
                    }
                    return result;
                };
                DecimalAndDmsConverter.prototype.ParseDms = function (raw) {
                    var result;
                    var rawUpper = raw.toUpperCase();
                    var rawStripped = rawUpper.replace(/[^0-9-\.]/ig, ' ').replace(/\s{2,}/ig, ' ').trim();
                    var directionType = this.GetDirectionTypeInput(rawUpper);
                    var coordinateParts = rawStripped.split(' ');
                    var firstNumber = parseFloat(coordinateParts[0]);
                    if(coordinateParts.length === 1) {
                        result = this.ToDmsFromCoordinate(directionType, firstNumber);
                    } else if(coordinateParts.length === 2) {
                        result = this.ToDmsFromDegreesMinutes(directionType, firstNumber, parseFloat(coordinateParts[1]));
                    } else if(coordinateParts.length === 3) {
                        result = this.ToDmsFromDegreesMinutesSeconds(directionType, firstNumber, parseFloat(coordinateParts[1]), parseFloat(coordinateParts[2]));
                    } else {
                        throw 'ParseDms Invalid Sections ' + raw;
                    }
                    return result;
                };
                DecimalAndDmsConverter.prototype.ToCoordinateDmsFromArray = function (coordinateParts) {
                    var latitudePart;
                    var longitudePart;
                    var coordinatePartsUsed = [];
                    for(var i = 0; i < coordinateParts.length; i++) {
                        var coordinatePart = coordinateParts[i];
                        if(this.HasDirectionType(coordinatePart)) {
                            var directionType = this.GetDirectionTypeInput(coordinatePart);
                            if(directionType == Enumerations.DirectionTypes.West || directionType == Enumerations.DirectionTypes.East) {
                                longitudePart = this.ParseDms(coordinatePart);
                                coordinatePartsUsed[i] = longitudePart;
                            } else {
                                latitudePart = this.ParseDms(coordinatePart);
                                coordinatePartsUsed[i] = latitudePart;
                            }
                        }
                    }
                    if(coordinatePartsUsed[0] == null) {
                        if(coordinatePartsUsed[1] == null) {
                            latitudePart = this.ParseDms("N" + coordinateParts[0]);
                            longitudePart = this.ParseDms("E" + coordinateParts[1]);
                            coordinatePartsUsed[0] = latitudePart;
                            coordinatePartsUsed[1] = longitudePart;
                        } else if(coordinatePartsUsed[1].DirectionType == Enumerations.DirectionTypes.West || coordinatePartsUsed[1].DirectionType == Enumerations.DirectionTypes.East) {
                            latitudePart = this.ParseDms("N" + coordinateParts[0]);
                            coordinatePartsUsed[0] = latitudePart;
                        } else {
                            longitudePart = this.ParseDms("E" + coordinateParts[0]);
                            coordinatePartsUsed[0] = longitudePart;
                        }
                    }
                    if(coordinatePartsUsed[1] == null) {
                        if(coordinatePartsUsed[0].DirectionType == Enumerations.DirectionTypes.West || coordinatePartsUsed[0].DirectionType == Enumerations.DirectionTypes.East) {
                            latitudePart = this.ParseDms("N" + coordinateParts[1]);
                        } else {
                            longitudePart = this.ParseDms("E" + coordinateParts[1]);
                        }
                    }
                    var result = new Model.CoordinateDmsInfo(latitudePart, longitudePart);
                    return result;
                };
                DecimalAndDmsConverter.prototype.ToDmsFromDegreesMinutesSeconds = function (directionType, degrees, minutes, seconds) {
                    var result;
                    var resultDirectionType = this.GetDirectionTypeOutput(directionType, degrees < 0);
                    return new Model.DmsInfo(resultDirectionType, Math.abs(degrees), minutes, seconds);
                };
                DecimalAndDmsConverter.prototype.ToDmsFromDegreesMinutes = function (directionType, degrees, minutes) {
                    var result;
                    var resultDirectionType = this.GetDirectionTypeOutput(directionType, degrees < 0);
                    return (new Model.DmInfo(resultDirectionType, Math.abs(degrees), minutes)).ToDms();
                };
                DecimalAndDmsConverter.prototype.ToDmsFromCoordinate = function (directionType, coordinate) {
                    var result;
                    var degrees;
                    var minutes;
                    var seconds;
                    var modDegrees = Math.abs(coordinate % 1);
                    var degrees = Math.round(Math.abs(coordinate) - modDegrees);
                    var rawMinutes = modDegrees * 60;
                    var modMinutes = rawMinutes % 1;
                    var minutes = Math.round(rawMinutes - modMinutes);
                    var seconds = parseFloat((modMinutes * 60).toPrecision(6));
                    var resultDirectionType = directionType;
                    resultDirectionType = this.GetDirectionTypeOutput(directionType, coordinate < 0);
                    return new Model.DmsInfo(resultDirectionType, Math.abs(degrees), minutes, seconds);
                };
                DecimalAndDmsConverter.prototype.HasDirectionType = function (raw) {
                    var rawUpper = raw.toUpperCase();
                    return (rawUpper.indexOf('N') >= 0 || rawUpper.indexOf('E') >= 0 || rawUpper.indexOf('S') >= 0 || rawUpper.indexOf('W') >= 0);
                };
                DecimalAndDmsConverter.prototype.GetDirectionTypeInput = function (raw) {
                    var rawUpper = raw.toUpperCase();
                    var directionType;
                    if(rawUpper.indexOf('N') >= 0) {
                        directionType = Enumerations.DirectionTypes.North;
                    } else if(rawUpper.indexOf('E') >= 0) {
                        directionType = Enumerations.DirectionTypes.East;
                    } else if(rawUpper.indexOf('S') >= 0) {
                        directionType = Enumerations.DirectionTypes.South;
                    } else if(rawUpper.indexOf('W') >= 0) {
                        directionType = Enumerations.DirectionTypes.West;
                    } else {
                        throw 'ParseDms Invalid Coordinate Format requires Direction ' + raw;
                    }
                    return directionType;
                };
                DecimalAndDmsConverter.prototype.GetDirectionTypeOutput = function (directionType, isNegative) {
                    var result = directionType;
                    if(isNegative && directionType == Enumerations.DirectionTypes.North) {
                        result = Enumerations.DirectionTypes.South;
                    } else if(isNegative && directionType == Enumerations.DirectionTypes.East) {
                        result = Enumerations.DirectionTypes.West;
                    } else if(isNegative && directionType == Enumerations.DirectionTypes.South) {
                        result = Enumerations.DirectionTypes.North;
                    } else if(isNegative && directionType == Enumerations.DirectionTypes.West) {
                        result = Enumerations.DirectionTypes.East;
                    }
                    return result;
                };
                return DecimalAndDmsConverter;
            })();
            Providers.DecimalAndDmsConverter = DecimalAndDmsConverter;            
        })(CoordinateConverter.Providers || (CoordinateConverter.Providers = {}));
        var Providers = CoordinateConverter.Providers;
        var CoordinateViewModel = (function () {
            function CoordinateViewModel(coordinateConverter, coordinateInputElement, gpsOutputElement, dmsOutputElement, decimalOutputElement, onInputChanged) {
                this._coordinateConverter = coordinateConverter;
                this._coordinateInputElement = coordinateInputElement;
                this._gpsOutputElement = gpsOutputElement;
                this._dmsOutputElement = dmsOutputElement;
                this._decimalOutputElement = decimalOutputElement;
                this._coordinateInputElement.onkeyup = onInputChanged;
            }
            CoordinateViewModel.prototype.Update = function (newValue) {
                try  {
                    if(newValue) {
                        this._coordinateInputElement.value = newValue;
                    }
                    this.Model = this.CoordinateConverter.ParseCoordinateDms(this.CoordinateInput);
                    this.CoordinateDecimalOutput = this.Model.ToCoordinateDecimal().ToString();
                    this.CoordinateGpsOutput = this.Model.ToCoordinateDm().ToString();
                    this.CoordinateDmsOutput = this.Model.ToCoordinateDms().ToString();
                } catch (ex) {
                    this.Model = null;
                    this.CoordinateDecimalOutput = '';
                    this.CoordinateGpsOutput = '';
                    this.CoordinateDmsOutput = '';
                }
            };
            Object.defineProperty(CoordinateViewModel.prototype, "CoordinateConverter", {
                get: function () {
                    return this._coordinateConverter;
                },
                enumerable: true,
                configurable: true
            });
            Object.defineProperty(CoordinateViewModel.prototype, "Model", {
                get: function () {
                    return this._model;
                },
                set: function (value) {
                    this._model = value;
                },
                enumerable: true,
                configurable: true
            });
            Object.defineProperty(CoordinateViewModel.prototype, "CoordinateInput", {
                get: function () {
                    return this._coordinateInputElement.value;
                },
                enumerable: true,
                configurable: true
            });
            Object.defineProperty(CoordinateViewModel.prototype, "CoordinateDecimalOutput", {
                set: function (value) {
                    this._decimalOutputElement.innerHTML = value;
                },
                enumerable: true,
                configurable: true
            });
            Object.defineProperty(CoordinateViewModel.prototype, "CoordinateGpsOutput", {
                set: function (value) {
                    this._gpsOutputElement.innerHTML = value;
                },
                enumerable: true,
                configurable: true
            });
            Object.defineProperty(CoordinateViewModel.prototype, "CoordinateDmsOutput", {
                set: function (value) {
                    this._dmsOutputElement.innerHTML = value;
                },
                enumerable: true,
                configurable: true
            });
            return CoordinateViewModel;
        })();
        CoordinateConverter.CoordinateViewModel = CoordinateViewModel;        
    })(Geo.CoordinateConverter || (Geo.CoordinateConverter = {}));
    var CoordinateConverter = Geo.CoordinateConverter;
})(Geo || (Geo = {}));
